package com.leshua.channel.mpos.common.utils;

import com.leshua.channel.mpos.utils.Base64Utils;
import com.leshua.channel.mpos.utils.RSAUtils;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;

/**
 * @author Devlin
 */
@Slf4j
public class RsaUtils {

    static final String mod = "CD97DF72B81897D326453B36F5B93C678141DAE5BAB2271DF30BF6483C80333DDCAE394D3F74AB7FD13222BED9F272C4DA118E4D399AEBA29CFA27252A93D5D8FF92501AC5655143B791CD2062CF82A9C9C8E5DD07B1E2D31E73FAB411270E3B4DA2D898CB53057AE28969D36D6C350425AD7A4A8D246B8E8D18C64FD31344CB";

    static final String testMode = "C3FC769CEF5522C596C2036D4524FF3D15875D44C67A6D630881798CB4669ADD516ED99ED3A37DDA95894EF91D96C3AF27173D0F9EA71280185C0520CE5428BA27131962B5876E3265F1DCC5BF746BE61A2BD4C0F031A699E812C72E93C8D9EF5DB8275756A8AF640BEA2C9696CC8BB41607E85A2D0C1751355A13970A682623";

    static final String publicE = "65537";

    static final String privateE = "52BE34E7EEBFB71AFBE41118E57C4F9B38A2507EF4CC8E81B737B13F115A67451673E80BF6E5F5BFD369E221FD855E3B6BA875250F721233B809D58757C377E4CC2CB7456AE3D78B912EA37F95DEB0AF9D668802CB598FA666C0D2F034A545210C60D91D7878AE8A093A6D4621B7C62A621877E68957DA57258FFE136887E701";

    static final String testprivateE = "B2D6BEF9E7DF7D5266867610110778ADA9E692F27E571B58425BBBA9ECB8B05A82C3AF6BA25E4F2AD647ACBBE007425BA3452E60017B1D83AC36D42B227C638819831627B4C7CD754F888270FD5DD4FEE0DDED81BA0341EDF73F6B4DDA6AD727C06457E3A07DB77493D677E6FD20671E2F7D513B775C47F61E83CE51338F23A9";


    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;


    static byte[] arr = {1, -119, 80, 79, 83, 48, 48, 48, 48, 54, 53, 108, 20, 15, -85, 65, -77, 87, -102, 53, -33, -69, -70, -74, 7, -9, -10, 64, -63, 42, 24, 104, -84, 86, 21, -102, 37, 94, -2, 52, -56, 1, 97, 37, -24, -19, 19, 103, -90, 34, -114, -122, 32, -23, -28, -35, -4, 38, 82, -1, 95, 57, -120, -57, -43, 92, 109, 110, -94, -128, -80, 10, -22, 29, 86, -4, -116, 20, 77, 79, 90, -120, 106, -26, -29, 55, 22, -87, 36, -119, 87, -39, 22, 22, -109, -108, -112, 39, 62, 64, -109, -15, 9, -84, -35, -59, -124, 24, -80, 45, 47, 73, 32, 97, 100, -15, 110, -42, 19, -40, -88, 0, -3, -98, 45, -108, -67, -24, 18, 126, 18, 48, -67, -7, 112, 22, -112, -22, 102, -107, -68, -11, 37, 36, -82, 42, -127, -15, 34, -38, 112, 85, -112, 44, -53, 3, 3, 106, 61, 71, 74, -27, -62, 13, 11, -19, 58, 74, -3, 55, 91, -5, -111, 56, -85, 31, 16, -120, 112, -112, -17, 96, -98, -116, -102, 49, -22, -64, -29, -5, 125, -41, -82, -46, -119, 69, 90, 114, -112, 85, -8, 18, 22, -51, 93, -25, 50, 3, -105, 94, -115, -108, -92, 16, 38, 101, -50, 52, 48, 40, -63, -116, 57, -60, 47, 116, -92, 85, -109, -32, 22, 16, -118, 79, -88, 38, -115, -108, -108, -50, -70, -95, -26, -19, -78, -1, 117, -14, -37, 112, -43, 77, -31, -78, 38, 107, 14, -124, 85, 38, -39, -86, -108, -103, -97, -81, 28, 102, -2, 49, -101, -109, 59, 75, -50, -38, 60, 104, -35, -64, -76, -127, -15, 117, -120, 104, 97, -33, -109, 15, 31, 82, -75, -81, 77, -14, -74, -56, 106, 19, 53, 68, -61, 46, 113, -28, 122, -116, 123, 82, 103, 115, 79, -34, 121, -31, -101, -27, 62, -114, 93, 120, -70, -86, 36, -47, 39, 72, -47, -15, -37, 93, -94, -41, -58, 50, 84, -82, 26, 50, -56, -91, -40, 44, -58, -31, -99, 89, 53, -123, 76, 66, 14, 67, -71, 5, -12, 6, -70, 80, -50, 51, -101, 87, -112, -59, -56, 72, -55, -7, -81, 61, -99, -56, 110, -68, 114, 0, -68, -12, -81, 76, -87, 90, -57, -43, -20, -86, -13, -85, -112, -41, 23, 57, 38};

    public static void main(String[] args) throws Exception {
        String message = new String(arr);
        System.out.println(message);
        log.info("========================加密====================================");
        String msg = "我123这个是测试xxxxxxxff??sdfdfdafafasf asdf afasdfasf asfsafasfas fasfsafa fas asfasfasf334343fdsafasfa sf as fasdfasdfafasf asfff1s6fsf56as5f6asf1as6fas6f1as1 1c16sdf1s5adfa6sf5a561vzxc33z16sd5f1sadf611ZC1z1c在1zv11s6v6s 66vs6f66sdf6s66 ?";
        message = message.substring(11);
        System.out.println(message);

        byte[] data = msg.getBytes();
        byte[] encodedData = RSAUtils.encryptByPublicKey(data, Base64Utils.encode(getPublicKey(testMode, publicE).getEncoded()));

        System.out.println("加密后文字：\r\n" + new String(encodedData));
        byte[] decodedData = RSAUtils.decryptByPrivateKey(message.getBytes(), Base64Utils.encode(getPrivateKey(testMode, testprivateE).getEncoded()));
        String target = new String(decodedData);
        System.out.println("解密后文字: \r\n" + target);

        log.info("公钥：{}", Base64Utils.encode(getPublicKey(mod, publicE).getEncoded()));
        log.info("私钥：{}", Base64Utils.encode(getPrivateKey(mod, privateE).getEncoded()));

//        String encMsg = RsaUtil.publicEncrypt(msg, getPublicKey(mod, publicE));
//        log.info("公钥加密后：{}", encMsg);
//        log.info("私钥解密后：{}", RsaUtil.privateDecrypt(encMsg, getPrivateKey(mod, privateE)));
//        log.info("========================签名===================================");
//        encMsg = RsaUtil.privateEncrypt(msg, getPrivateKey(mod, privateE));
//        log.info("私钥签名后：{}", encMsg);
//        log.info("私钥解密后：{}", RsaUtil.publicDecrypt(encMsg, getPublicKey(mod, publicE)));
    }


    /**
     * 生成公钥和私钥信息
     */
    public static void generateKeyPair(String msg) throws Exception {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
        }
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        BigInteger publicMod = publicKey.getModulus();
        BigInteger publicExp = publicKey.getPublicExponent();

        BigInteger privateMod = privateKey.getModulus();
        BigInteger privateExp = privateKey.getPrivateExponent();

        System.out.println("publicKey Mod: " + publicMod);
        System.out.println("publicKey Exp: " + publicExp);
        System.out.println("privateKey Mod: " + privateMod);
        System.out.println("privateKey Exp: " + privateExp);

        log.info("");
        log.info("===============正常秘钥===============================");
        // 得到公钥字符串
        String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
        log.info("公钥：{}", publicKeyString);
        log.info("公钥加密：==================================================");
        String encMsg = RsaUtil.publicEncrypt(msg, RsaUtil.getPublicKey(publicKeyString));
        log.info("加密后：{}", encMsg);

        // 得到私钥字符串
        String privateKeyString = new String(Base64.getEncoder().encode(privateKey.getEncoded()));
        log.info("私钥：{}", privateKeyString);
        log.info("私钥解密：===================================================");
        log.info("解密后：{}", RsaUtil.privateDecrypt(encMsg, RsaUtil.getPrivateKey(privateKeyString)));
        log.info("=================正常秘钥================================");
        log.info("");
        testEncDec(msg, publicMod, publicExp, privateMod, privateExp);
    }

    private static void testEncDec(String msg, BigInteger publicMod, BigInteger publicExp, BigInteger privateMod, BigInteger privateExp) throws Exception {
        log.info("原文: {}", msg);
        String ecnMsg = publicEncrypt(publicMod, publicExp, msg);
        log.info("公钥加密后：{}", ecnMsg);
        String decMsg = privateDecrypt(privateMod, privateExp, ecnMsg);
        log.info("私钥解密后: {}", decMsg);
        log.info("=============================================================");

        ecnMsg = privateEncrypt(privateMod, privateExp, msg);
        log.info("私钥加密：{}", ecnMsg);
        decMsg = publicDecrypt(publicMod, publicExp, ecnMsg);
        log.info("公钥解密: {}", decMsg);
    }

    /**
     * 公钥加密
     *
     * @param publicModules
     * @param publicExponent
     * @param str
     * @return
     * @throws Exception
     */
    public static String publicEncrypt(BigInteger publicModules, BigInteger publicExponent, String str) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(publicModules, publicExponent);
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptData = cipher.doFinal(str.getBytes());
        //base64加密
        return Base64.getEncoder().encodeToString(encryptData);
    }

    /**
     * 公钥解密
     *
     * @param publicModules
     * @param publicExponent
     * @param str
     * @return
     * @throws Exception
     */
    public static String publicDecrypt(BigInteger publicModules, BigInteger publicExponent, String str) throws Exception {
        return privateDecrypt(publicModules, publicExponent, str);
    }

    /**
     * 私钥加密
     *
     * @param privateModules
     * @param privateExponent
     * @param str
     * @return
     * @throws Exception
     */
    public static String privateEncrypt(BigInteger privateModules, BigInteger privateExponent, String str) throws Exception {
        return publicEncrypt(privateModules, privateExponent, str);
    }

    /**
     * 私钥解密
     *
     * @param privateModules
     * @param privateExponent
     * @param str
     * @return
     * @throws Exception
     */
    public static String privateDecrypt(BigInteger privateModules, BigInteger privateExponent, String str) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(privateModules, privateExponent);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        //base64解密
        byte[] encryptData = Base64.getDecoder().decode(str);
        byte[] decryptData = cipher.doFinal(encryptData);
        return new String(decryptData);
    }


    /**
     * 获取公钥
     *
     * @param modulus
     * @param publicExponent
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPublicKey getPublicKey(String modulus, String publicExponent)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        BigInteger bigIntModulus = new BigInteger(modulus, 16);
        BigInteger bigIntPublicExponent = new BigInteger(publicExponent);
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPublicExponent);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return (RSAPublicKey) publicKey;
    }

    /**
     * 获取私钥
     *
     * @param modulus
     * @param privateExponent
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPrivateKey getPrivateKey(String modulus, String privateExponent)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        BigInteger bigIntModulus = new BigInteger(modulus, 16);
        BigInteger bigIntPrivateExponent = new BigInteger(privateExponent, 16);
        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(bigIntModulus, bigIntPrivateExponent);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return (RSAPrivateKey) privateKey;
    }


}
